package com.yc.spring.aop;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

//切面类 = 切点(方法或注解属性) + 增强（方法）
@Aspect
@Component
public class MyAspect {

    //前置增强
    @Before("execution(* com.yc..dao.*.*(..))")
    public void before(){
        System.out.println("前置拦截");
    }

    //spring  会以接口注入方式，将连接点对象注入进来
    @Before("myPointcut()")
    public void before1(JoinPoint jp){
        //参数
        System.out.println("Arrays.toString(jp.getArgs()) = " + Arrays.toString(jp.getArgs()));
        //方法签名
        System.out.println("jp.getSignature() = " + jp.getSignature());
        //目标对象
        System.out.println("jp.getTarget() = " + jp.getTarget());
        System.out.println("-----前置拦截 end----");
    }


    //后置增强
    @After("myPointcut()")
    public void after(JoinPoint jp){
        System.out.println("---------后置拦截 "+jp.getSignature()+".-------");
    }

    //切点方法
    @Pointcut("execution(* com.yc.spring.bbs.dao.UserDaoImpl.select*(..))")
    public void myPointcut(){

    }

    //返回拦截  =>只有业务方法执行成功才拦截，并且可以注入业务方法的返回值
    @AfterReturning(value = "myPointcut()",returning = "ret")  //引用切点
    public void afterReturning(JoinPoint jp,Object ret){
        System.out.println("------返回拦截"+jp.getSignature()+"----------");
        System.out.println("------返回拦截"+ret+"----------");

    }

    //异常拦截  只有业务方法执行出现异常才拦截，并且可以注入异常
    @AfterThrowing(value = "myPointcut()",throwing = "e")  //引用切点
    public void afterReturning(JoinPoint jp,Throwable e){
        System.out.println("------异常拦截"+jp.getSignature()+"----------");
        System.out.println("------异常拦截"+e+"----------");

    }

    //环绕增强
    //返回值：是业务方法的返回值
    //连接点对象负责执行业务方法  必须手动执行
    @Around("execution(* com.yc.spring.bbs.dao.UserDaoImpl.count(..))")
    public Object around(ProceedingJoinPoint pjp){
        try {
            System.out.println("环绕增强=》前置增强");
            long time =System.currentTimeMillis();
            //执行业务方法
            Object ret = pjp.proceed();
            time = System.currentTimeMillis() - time;
            System.out.println(pjp+"业务执行了:"+time+"毫秒");
            System.out.println("环绕增强=》返回增强");
            return ret;
        } catch (Throwable e) {
            System.out.println("环绕增强=》异常增强");
            throw new RuntimeException(e);

        }
        finally {
            System.out.println("环绕增强=》后置增强");
        }


    }

    // 前置增强
    @Before("execution(* com.yc..biz.UserBiz.*(..))")
    public void before1(){
        System.out.println("前置拦截");
    }



}
